﻿package code {
	import flash.geom.Rectangle;
	import flash.events.*;	
	// creates the ball
	public class Ball extends GameObject {
		private const GRAVITY:Number = 1;
		private const MAX_FALL:Number = 2000;
		private const BOUNCE:Number = -1.15;
		private var mass:int;
		public var reset, launched, gravityIsOn, hasLaunched:Boolean;	  // reset, launched, gravity on, and launched
		
		//HUD Update variables
		public var score:Number = 0;
		public var ballsLeft:Number = 3;
		
		//Collision variables
		private var xBound:Number = 665;
		private var radius:Number = 30;
		
		// center of circle
		private var center:Vertex;
		
		private var velocity:Vertex;
		
		private var dt:Number;
		
		private var collisionPoint:Vertex;
		
		public function Ball(shapeType:String, radius:Number, sides:Number, color:uint, thickness:Number, hollow:Boolean) {
			super(shapeType, radius, sides, color, thickness, hollow);
			mass = 5;
			launched = true;
			hasLaunched = false;
			gravityIsOn = false;
			reset = true; //Is the ball being reset?
			addEventListener(MouseEvent.MOUSE_DOWN, dragBall);
			addEventListener(MouseEvent.MOUSE_UP, undragBall);
		}
		
		public function dragBall(e:Event){
			startDrag();
			vx = 0;
			vy = 0;
			gravityIsOn = false;
		}
		
		public function undragBall(e:Event){
			stopDrag();
			gravityIsOn = true;
		}
		
		// launched the ball by changing variables
		public function launch(){
			launched = false;
			hasLaunched = true;
			reset = true;
		
		}
		
		public function update(collisionObjects:Array, currentTime:Number){
			currentTime = currentTime / 100;
			
			checkCollision(collisionObjects);
			//dt = currentTime;
			moveBall(currentTime);
		}
		
		// moves the ball using euler and time
		public function moveBall(currentTime:Number){
			
			if(gravityIsOn && vy < MAX_FALL){
				vy += GRAVITY;
			}

			x += vx * currentTime;  // changes velocity over time
			y += vy * currentTime;
		}
		
		// checks all collision
		public function checkCollision(collisionObjects:Array){		
			for each(var l:Line in collisionObjects)
			{
				/*var dx:Number = go.x - x;
				var dy:Number = go.y - y;
				var dist:Number = Math.sqrt(dx*dx + dy*dy);*/
			

				
				//if(hitTestObject(go)){  // then there is collision					
					//for each(var l:Line in go.shape.linesArray){
						if(l.a != null && l.b != null){
							// sets up variables by calculating them
							getCenter();  // calculates current center of ball
							getVelocity(); // calcualtes current velocity vector of ball
							l.getNormal(); // calculates normal vector of ball
							l.getPoint(); // calculates pointD on line 
							var onLine:Number = closestPointSegment(l);
							if(onLine < 1 && onLine > 0){
								if(checkLine(l) && dt < 1 && dt >= 0){
									trace("DT: " + dt);
									affectBall(l);
									//If ball has reached the bottom of the table, reset.
									/*if(y > stage.stageHeight - radius && x < xBound)
									{
										ballsLeft --; //Lose one "life"
										reset = false; //Reset the ball
										hasLaunched = false;
										break;
									}							
									
									//Change the color of the object once hit
									if(go.shapeType == "Polygon") //only change polygons
									{
										score+= 10; //get points for each hit
										go.shape.color = Math.random() * 0xFFFFFF;; //Each collision produces random colors for objects
										go.shape.renderVertices(); //Redraw with updated color
										go.deform(1.25);
									}
									*/
									
									break;
								}
							}
						}
					//}					
				//}
			}
		}
		
		public function getCenter(){
			center = new Vertex(x, y );
		}
		
		public function getVelocity(){
			velocity = new Vertex(vx, vy);
		}
		
		// from Real Time Collision Detection
		// int IntersectMovingSpherePlane(Sphere s, Vector v, Plane p, float &t, Point &q)
		// Sphere = ball, Vector = velocity vector, Plane = p, t = dt (change in time), point = origin + velocity vector
		public function checkLine(line:Line):Boolean{

			var dist:Number = Vertex.dot(line.normal, center) - line.pointD;  //  float dist = Dot(p.n, s.c) - p.d;
			if(Math.abs(dist) <= shape.radius){
				dt = 0;
				collisionPoint = center;

				return true;
			}
			else{
				var denom:Number = Vertex.dot(line.normal, velocity); // gets scalar of the normal vector of line and velocity vector to see where they hit
				if(denom * dist >= 0){  // if the ball is moving away they do not hit
					return false;
					
				}
				else{  // it must be moving towards plane
					var centerToPlane:Number = dist > 0 ? shape.radius : -shape.radius;
					dt = (centerToPlane - dist) / denom;  // the time it hit is the change in location over the place where the velocity vector and normal meet
					var centerVelocityTime:Vertex = Vertex.add(center, Vertex.multiply(dt, velocity));  // s.c + t * v
					var centerToPlaneNormal:Vertex = Vertex.multiply(centerToPlane, line.normal);
					
					collisionPoint = Vertex.subtract(centerToPlaneNormal, centerVelocityTime);
					
					return true;
				}
			}
		}
		
		public function closestPointSegment(line:Line):Number{
			var ab:Vertex = Vertex.subtract(line.b, line.a);
			var ifHits:Number;
			ifHits = Vertex.dot(Vertex.subtract(center, line.a), ab) / Vertex.dot(ab, ab);
			if(ifHits < 0){
				ifHits = 0;
			}
			if(ifHits > 1){
				ifHits = 1;
			}
			
			return ifHits;
			//return Vertex.add(line.a , Vertex.multiply(t, ab)); will return point that it hits
		}
		
		// checks against lines the array
		public function zzzcheckLine(line:Line):Boolean{
			
			if(hitTestObject(line)){  // from schwartz
				
				var angle:Number = line.getAngle();

				var cos:Number = Math.cos(angle);
				var sin:Number = Math.sin(angle);
				
				var x1:Number = x - line.a.x;
				var y1:Number = y - line.a.y;
				
				var y2:Number = cos * y1 - sin * x1;
				
				var vy1:Number = cos * vy - sin * vx;
				
				if((y2 > -shape.radius && y2 < vy1)){
					var x2:Number = cos * x1 + sin * y1;
					
					var vx1:Number = cos * vx + sin * vy;
					
					y2 = -shape.radius;
					
					vy1 *= BOUNCE;
					x1 = cos * x2 - sin * y2;
					y1 = cos * y2 + sin * x2;
					vx = cos * vx1 - sin * vy1;
					vy = cos * vy1 + sin * vx1;
					x = line.a.x + x1;
					y = line.a.y + y1;
					return true;
				}
			}
			return false;
		}
		
		public function affectBall(line:Line){
			
				var angle:Number = line.getAngle();

				var cos:Number = Math.cos(angle);
				var sin:Number = Math.sin(angle);
				
				var x1:Number = x - line.a.x;
				var y1:Number = y - line.a.y;
				
				var y2:Number = cos * y1 - sin * x1;
				
				var vy1:Number = cos * vy - sin * vx;
				
				//if((y2 > -shape.radius && y2 < vy1)){
					var x2:Number = cos * x1 + sin * y1;
					
					var vx1:Number = cos * vx + sin * vy;
					
					y2 = -shape.radius;
					
					vy1 *= BOUNCE;
					x1 = cos * x2 - sin * y2;
					y1 = cos * y2 + sin * x2;
					vx = cos * vx1 - sin * vy1;
					vy = cos * vy1 + sin * vx1;
					x = line.a.x + x1;
					y = line.a.y + y1;
					trace("Hit: " + (line.a.x + x1));
					//return true;
				//}
		}
	}	
}
